/*
 * Gedigarr - Falling block game.
 * Copyright (C) 2010  BoredCorp
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * 
 * r2 : 2010-04-22 
 *  Added keyStates range checking. The only keys outside the 256 bound are 
 *   useless keys (menu and windows) if i need them, ill change more.
 */
package gedigarr.input;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * Key listener adapter. Stores current state of keys.
 * <p>
 * The following states are supported:
 * <ul>
 * <li>STATE_NONE: no state.</li>
 * <li>STATE_PRESSED: the key was first pressed this update.</li>
 * <li>STATE_RELEASED: the key was pressed last update and now is not - not supported heh</li>
 * <li>STATE_HELD: the key was pressed on the last update and still is.</li>
 * </ul>
 * <p>
 * They can be read using InputHandler.getKeyState(int), which takes the 
 * KeyEvent key code as an argument.
 * 
 *  
 * @author JC
 */
public class InputHandler implements KeyListener {

  public static final int STATE_NONE = 0;
  public static final int STATE_PRESSED = KeyEvent.KEY_PRESSED;
  public static final int STATE_RELEASED = KeyEvent.KEY_RELEASED;
  public static final int STATE_HELD = 1;
  int[] keyStates = new int[ 256 ];
  int[] lastKeyStates = new int[ 256 ];
  private static InputHandler self = null;

  private InputHandler() {
  }

  public static InputHandler getInstance() {
    if ( self == null ) {
      self = new InputHandler();
    }
    return self;
  }

  public int getKeyState( int keyCode ) {
    //return if the key stroke is outside the boundaries. This happens for 
    // platform specific keys (menu key/windows key) will change fundamentals
    // if these keys are required
    if ( keyCode >= keyStates.length ) {
      return STATE_NONE;
    }
    return keyStates[keyCode];
  }

  public void keyTyped( KeyEvent e ) {

  }

  public void keyPressed( KeyEvent e ) {
    int keyCode = e.getKeyCode();
    //return if the key stroke is outside the boundaries. This happens for 
    // platform specific keys (menu key/windows key) will change fundamentals
    // if these keys are required
    if ( keyCode >= keyStates.length ) {
      return;
    }
    if ( keyStates[keyCode] == STATE_PRESSED || keyStates[keyCode] == STATE_HELD ) {
      keyStates[keyCode] = STATE_HELD;
    } else {
      keyStates[keyCode] = STATE_PRESSED;
    }
  }

  public void keyReleased( KeyEvent e ) {
    int keyCode = e.getKeyCode();
    //return if the key stroke is outside the boundaries. This happens for 
    // platform specific keys (menu key/windows key) will change fundamentals
    // if these keys are required
    if ( keyCode >= keyStates.length ) {
      return;
    }
    keyStates[e.getKeyCode()] = STATE_RELEASED;
  }

  public void pollPressed() {
    for ( int i = 0; i < keyStates.length; i++ ) {
      if ( keyStates[i] == STATE_PRESSED && lastKeyStates[i] == STATE_PRESSED ) {
        keyStates[i] = STATE_HELD;
      }
      if ( keyStates[i] == STATE_RELEASED && lastKeyStates[i] == STATE_RELEASED ) {
        keyStates[i] = STATE_NONE;
      }
      lastKeyStates[i] = keyStates[i];
    }
  }
}
